{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Operators"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:02:56.554914Z",
     "start_time": "2019-08-21T09:02:54.249612Z"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister\n",
    "from qiskit import execute, BasicAer\n",
    "from qiskit.compiler import transpile\n",
    "from qiskit.quantum_info.operators import Operator, Pauli\n",
    "from qiskit.quantum_info import process_fidelity\n",
    "\n",
    "from qiskit.extensions import RXGate, XGate, CXGate"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Operator Class\n",
    "\n",
    "The `Operator` class is used in Qiskit to represent matrix operators acting on a quantum system. It has several methods to build composite operators using tensor products of smaller operators, and to compose operators.\n",
    "\n",
    "### Creating Operators\n",
    "\n",
    "The easiest way to create an operator object is to initialize it with a matrix given as a list or a Numpy array. For example, to create a two-qubit Pauli-XX operator:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:02:56.572857Z",
     "start_time": "2019-08-21T09:02:56.566140Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\n",
       "          [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],\n",
       "          [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\n",
       "          [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]],\n",
       "         input_dims=(2, 2), output_dims=(2, 2))"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "XX = Operator([[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]])\n",
    "XX"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Operator Properties\n",
    "\n",
    "The operator object stores the underlying matrix, and the input and output dimension of subsystems. \n",
    "\n",
    "* `data`: To access the underlying Numpy array, we may use the `Operator.data` property.\n",
    "* `dims`: To return the total input and output dimension of the operator, we may use the `Operator.dim` property. *Note: the output is returned as a tuple `(input_dim, output_dim)`, which is the reverse of the shape of the underlying matrix.*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:02:56.589962Z",
     "start_time": "2019-08-21T09:02:56.585681Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\n",
       "       [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],\n",
       "       [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\n",
       "       [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "XX.data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:02:56.615497Z",
     "start_time": "2019-08-21T09:02:56.611146Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(4, 4)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "input_dim, output_dim = XX.dim\n",
    "input_dim, output_dim"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Input and Output Dimensions\n",
    "\n",
    "The operator class also keeps track of subsystem dimensions, which can be used for composing operators together. These can be accessed using the `input_dims` and `output_dims` functions.\n",
    "\n",
    "For $2^N$ by $2^M$ operators, the input and output dimension will be automatically assumed to be M-qubit and N-qubit:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:02:56.804167Z",
     "start_time": "2019-08-21T09:02:56.798857Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Input dimensions: (2, 2)\n",
      "Output dimensions: (2,)\n"
     ]
    }
   ],
   "source": [
    "op = Operator(np.random.rand(2 ** 1, 2 ** 2))\n",
    "print('Input dimensions:', op.input_dims())\n",
    "print('Output dimensions:', op.output_dims())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the input matrix is not divisible into qubit subsystems, then it will be stored as a single-qubit operator. For example, if we have a $6\\times6$ matrix:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:02:57.764881Z",
     "start_time": "2019-08-21T09:02:57.760401Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Input dimensions: (6,)\n",
      "Output dimensions: (6,)\n"
     ]
    }
   ],
   "source": [
    "op = Operator(np.random.rand(6, 6))\n",
    "print('Input dimensions:', op.input_dims())\n",
    "print('Output dimensions:', op.output_dims())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The input and output dimension can also be manually specified when initializing a new operator:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:02:58.292849Z",
     "start_time": "2019-08-21T09:02:58.287354Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Input dimensions: (4,)\n",
      "Output dimensions: (2,)\n"
     ]
    }
   ],
   "source": [
    "# Force input dimension to be (4,) rather than (2, 2)\n",
    "op = Operator(np.random.rand(2 ** 1, 2 ** 2), input_dims=[4])\n",
    "print('Input dimensions:', op.input_dims())\n",
    "print('Output dimensions:', op.output_dims())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:02:58.779572Z",
     "start_time": "2019-08-21T09:02:58.774878Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Input dimensions: (2, 3)\n",
      "Output dimensions: (2, 3)\n"
     ]
    }
   ],
   "source": [
    "# Specify system is a qubit and qutrit\n",
    "op = Operator(np.random.rand(6, 6),\n",
    "              input_dims=[2, 3], output_dims=[2, 3])\n",
    "print('Input dimensions:', op.input_dims())\n",
    "print('Output dimensions:', op.output_dims())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also extract just the input or output dimensions of a subset of subsystems using the `input_dims` and `output_dims` functions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:03:02.187313Z",
     "start_time": "2019-08-21T09:03:02.183719Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dimension of input system 0: (2,)\n",
      "Dimension of input system 1: (3,)\n"
     ]
    }
   ],
   "source": [
    "print('Dimension of input system 0:', op.input_dims([0]))\n",
    "print('Dimension of input system 1:', op.input_dims([1]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Converting classes to Operators\n",
    "\n",
    "Several other classes in Qiskit can be directly converted to an `Operator` object using the operator initialization method. For example:\n",
    "\n",
    "* `Pauli` objects\n",
    "* `Gate` and `Instruction` objects\n",
    "* `QuantumCircuits` objects\n",
    "\n",
    "Note that the last point means we can use the `Operator` class as a unitary simulator to compute the final unitary matrix for a quantum circuit, without having to call a simulator backend. If the circuit contains any unsupported operations, an exception will be raised. Unsupported operations are: measure, reset, conditional operations, or a gate that does not have a matrix definition or decomposition in terms of gate with matrix definitions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:03:02.854419Z",
     "start_time": "2019-08-21T09:03:02.842387Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\n",
       "          [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],\n",
       "          [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\n",
       "          [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]],\n",
       "         input_dims=(2, 2), output_dims=(2, 2))"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create an Operator from a Pauli object\n",
    "\n",
    "pauliXX = Pauli(label='XX')\n",
    "Operator(pauliXX)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:03:03.064145Z",
     "start_time": "2019-08-21T09:03:03.058953Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n",
       "          [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\n",
       "          [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],\n",
       "          [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]],\n",
       "         input_dims=(2, 2), output_dims=(2, 2))"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create an Operator for a Gate object\n",
    "Operator(CXGate())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:03:03.353613Z",
     "start_time": "2019-08-21T09:03:03.345462Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[0.70710678+0.j        , 0.        -0.70710678j],\n",
       "          [0.        -0.70710678j, 0.70710678+0.j        ]],\n",
       "         input_dims=(2,), output_dims=(2,))"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create an operator from a parameterized Gate object\n",
    "Operator(RXGate(np.pi / 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:03:47.550069Z",
     "start_time": "2019-08-21T09:03:47.408126Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[ 0.70710678+0.j,  0.70710678+0.j,  0.        +0.j, ...,\n",
       "            0.        +0.j,  0.        +0.j,  0.        +0.j],\n",
       "          [ 0.        +0.j,  0.        +0.j,  0.70710678+0.j, ...,\n",
       "            0.        +0.j,  0.        +0.j,  0.        +0.j],\n",
       "          [ 0.        +0.j,  0.        +0.j,  0.        +0.j, ...,\n",
       "            0.        +0.j,  0.        +0.j,  0.        +0.j],\n",
       "          ...,\n",
       "          [ 0.        +0.j,  0.        +0.j,  0.        +0.j, ...,\n",
       "            0.        +0.j,  0.        +0.j,  0.        +0.j],\n",
       "          [ 0.        +0.j,  0.        +0.j,  0.70710678+0.j, ...,\n",
       "            0.        +0.j,  0.        +0.j,  0.        +0.j],\n",
       "          [ 0.70710678+0.j, -0.70710678+0.j,  0.        +0.j, ...,\n",
       "            0.        +0.j,  0.        +0.j,  0.        +0.j]],\n",
       "         input_dims=(2, 2, 2, 2, 2, 2, 2, 2, 2, 2), output_dims=(2, 2, 2, 2, 2, 2, 2, 2, 2, 2))"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create an operator from a QuantumCircuit object\n",
    "circ = QuantumCircuit(10)\n",
    "circ.h(0)\n",
    "for j in range(1, 10):\n",
    "    circ.cx(j-1, j)\n",
    "\n",
    "# Convert circuit to an operator by implicit unitary simulation\n",
    "Operator(circ)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using Operators in circuits\n",
    "\n",
    "Unitary `Operators` can be directly inserted into a `QuantumCircuit` using the `QuantumCircuit.append` method. This converts the `Operator` into a `UnitaryGate` object, which is added to the circuit.\n",
    "\n",
    "If the operator is not unitary, an exception will be raised. This can be checked using the `Operator.is_unitary()` function, which will return `True` if the operator is unitary and `False` otherwise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:03:49.196556Z",
     "start_time": "2019-08-21T09:03:49.161398Z"
    },
    "tags": [
     "nbsphinx-thumbnail"
    ]
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 418.992x204.68 with 1 Axes>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create an operator\n",
    "XX = Operator(Pauli(label='XX'))\n",
    "\n",
    "# Add to a circuit\n",
    "circ = QuantumCircuit(2, 2)\n",
    "circ.append(XX, [0, 1])\n",
    "circ.measure([0,1], [0,1])\n",
    "circ.draw('mpl')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that in the above example we initialize the operator from a `Pauli` object. However, the `Pauli` object may also be directly inserted into the circuit itself and will be converted into a sequence of single-qubit Pauli gates:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'11': 1024}"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "backend = BasicAer.get_backend('qasm_simulator')\n",
    "job = execute(circ, backend, basis_gates=['u1','u2','u3','cx'])\n",
    "job.result().get_counts(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:12.017240Z",
     "start_time": "2019-08-21T09:04:11.989825Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"word-wrap: normal;white-space: pre;background: #fff0;line-height: 1.1;font-family: &quot;Courier New&quot;,Courier,monospace\">     ┌───────────┐┌─┐   \n",
       "q_0: ┤0          ├┤M├───\n",
       "     │  Pauli:XX │└╥┘┌─┐\n",
       "q_1: ┤1          ├─╫─┤M├\n",
       "     └───────────┘ ║ └╥┘\n",
       "c: 2/══════════════╩══╩═\n",
       "                   0  1 </pre>"
      ],
      "text/plain": [
       "     ┌───────────┐┌─┐   \n",
       "q_0: ┤0          ├┤M├───\n",
       "     │  Pauli:XX │└╥┘┌─┐\n",
       "q_1: ┤1          ├─╫─┤M├\n",
       "     └───────────┘ ║ └╥┘\n",
       "c: 2/══════════════╩══╩═\n",
       "                   0  1 "
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Add to a circuit\n",
    "circ2 = QuantumCircuit(2, 2)\n",
    "circ2.append(Pauli(label='XX'), [0, 1])\n",
    "circ2.measure([0,1], [0,1])\n",
    "circ2.draw()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Combining Operators\n",
    "\n",
    "Operators may be combined using several methods. \n",
    "\n",
    "### Tensor Product\n",
    "\n",
    "Two operators $A$ and $B$ may be combined into a tensor product operator $A\\otimes B$ using the `Operator.tensor` function. Note that if both A and B are single-qubit operators, then `A.tensor(B)` = $A\\otimes B$ will have the subsystems indexed as matrix B  on subsystem 0, and matrix $A$ on subsystem 1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:14.208734Z",
     "start_time": "2019-08-21T09:04:14.201058Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[ 0.+0.j,  0.+0.j,  1.+0.j,  0.+0.j],\n",
       "          [ 0.+0.j, -0.+0.j,  0.+0.j, -1.+0.j],\n",
       "          [ 1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j],\n",
       "          [ 0.+0.j, -1.+0.j,  0.+0.j, -0.+0.j]],\n",
       "         input_dims=(2, 2), output_dims=(2, 2))"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = Operator(Pauli(label='X'))\n",
    "B = Operator(Pauli(label='Z'))\n",
    "A.tensor(B)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tensor Expansion\n",
    "\n",
    "A closely related operation is `Operator.expand`, which acts like a tensor product but in the reverse order. Hence, for two operators $A$ and $B$ we have `A.expand(B)` = $B\\otimes A$ where the subsystems indexed as matrix A  on subsystem 0, and matrix $B$ on subsystem 1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:14.899024Z",
     "start_time": "2019-08-21T09:04:14.891072Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[ 0.+0.j,  1.+0.j,  0.+0.j,  0.+0.j],\n",
       "          [ 1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j, -0.+0.j, -1.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j, -1.+0.j, -0.+0.j]],\n",
       "         input_dims=(2, 2), output_dims=(2, 2))"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = Operator(Pauli(label='X'))\n",
    "B = Operator(Pauli(label='Z'))\n",
    "A.expand(B)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Composition\n",
    "\n",
    "We can also compose two operators $A$ and $B$ to implement matrix multiplication using the `Operator.compose` method. We have that `A.compose(B)` returns the operator with matrix $B.A$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:15.655155Z",
     "start_time": "2019-08-21T09:04:15.648295Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[ 0.+0.j,  1.+0.j],\n",
       "          [-1.+0.j,  0.+0.j]],\n",
       "         input_dims=(2,), output_dims=(2,))"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = Operator(Pauli(label='X'))\n",
    "B = Operator(Pauli(label='Z'))\n",
    "A.compose(B)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also compose in the reverse order by applying $B$ in front of $A$ using the `front` kwarg of `compose`:  `A.compose(B, front=True)` = $A.B$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:16.460560Z",
     "start_time": "2019-08-21T09:04:16.452319Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[ 0.+0.j, -1.+0.j],\n",
       "          [ 1.+0.j,  0.+0.j]],\n",
       "         input_dims=(2,), output_dims=(2,))"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = Operator(Pauli(label='X'))\n",
    "B = Operator(Pauli(label='Z'))\n",
    "A.compose(B, front=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Subsystem Composition\n",
    "\n",
    "Note that the previous compose requires that the total output dimension of the first operator $A$ is equal to total input dimension of the composed operator $B$ (and similarly, the output dimension of $B$ must be equal to the input dimension of $A$ when composing with `front=True`).\n",
    "\n",
    "We can also compose a smaller operator with a selection of subsystems on a larger operator using the `qargs` kwarg of `compose`, either with or without `front=True`. In this case, the relevant input and output dimensions of the subsystems being composed must match. *Note that the smaller operator must always be the argument of `compose` method.*\n",
    "\n",
    "For example, to compose a two-qubit gate with a three-qubit Operator:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:17.113510Z",
     "start_time": "2019-08-21T09:04:17.105398Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[ 0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  1.+0.j,  0.+0.j,  0.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j, -1.+0.j,  0.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  1.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,\n",
       "           -1.+0.j],\n",
       "          [ 1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j, -1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j,  1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j,  0.+0.j, -1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,\n",
       "            0.+0.j]],\n",
       "         input_dims=(2, 2, 2), output_dims=(2, 2, 2))"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Compose XZ with an 3-qubit identity operator\n",
    "op = Operator(np.eye(2 ** 3))\n",
    "XZ = Operator(Pauli(label='XZ'))\n",
    "op.compose(XZ, qargs=[0, 2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:17.324353Z",
     "start_time": "2019-08-21T09:04:17.315952Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[ 0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  1.+0.j,  0.+0.j,  0.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j, -1.+0.j,  0.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  1.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,\n",
       "           -1.+0.j],\n",
       "          [ 1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j, -1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j,  1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,\n",
       "            0.+0.j],\n",
       "          [ 0.+0.j,  0.+0.j,  0.+0.j, -1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,\n",
       "            0.+0.j]],\n",
       "         input_dims=(2, 2, 2), output_dims=(2, 2, 2))"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Compose YX in front of the previous operator\n",
    "op = Operator(np.eye(2 ** 3))\n",
    "YX = Operator(Pauli(label='YX'))\n",
    "op.compose(XZ, qargs=[0, 2], front=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Linear combinations\n",
    "\n",
    "Operators may also be combined using standard linear operators for addition, subtraction and scalar multiplication by complex numbers. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:18.829988Z",
     "start_time": "2019-08-21T09:04:18.812834Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[-1.5+0.j,  0. +0.j,  0. +0.j,  0. +0.j],\n",
       "          [ 0. +0.j,  1.5+0.j,  1. +0.j,  0. +0.j],\n",
       "          [ 0. +0.j,  1. +0.j,  1.5+0.j,  0. +0.j],\n",
       "          [ 0. +0.j,  0. +0.j,  0. +0.j, -1.5+0.j]],\n",
       "         input_dims=(2, 2), output_dims=(2, 2))"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "XX = Operator(Pauli(label='XX'))\n",
    "YY = Operator(Pauli(label='YY'))\n",
    "ZZ = Operator(Pauli(label='ZZ'))\n",
    "\n",
    "op = 0.5 * (XX + YY - 3 * ZZ)\n",
    "op"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An important point is that while `tensor`, `expand` and `compose` will preserve the unitarity of unitary operators, linear combinations will not; hence, adding two unitary operators will, in general, result in a non-unitary operator:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:19.151814Z",
     "start_time": "2019-08-21T09:04:19.147497Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "op.is_unitary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Implicit Conversion to Operators\n",
    "\n",
    "Note that for all the following methods, if the second object is not already an `Operator` object, it will be implicitly converted into one by the method. This means that matrices can be passed in directly without being explicitly converted to an `Operator` first. If the conversion is not possible, an exception will be raised."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:20.045005Z",
     "start_time": "2019-08-21T09:04:20.039841Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Operator([[0.+0.j, 1.+0.j],\n",
       "          [1.+0.j, 0.+0.j]],\n",
       "         input_dims=(2,), output_dims=(2,))"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Compose with a matrix passed as a list\n",
    "Operator(np.eye(2)).compose([[0, 1], [1, 0]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comparison of Operators\n",
    "\n",
    "Operators implement an equality method that can be used to check if two operators are approximately equal. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:20.821642Z",
     "start_time": "2019-08-21T09:04:20.815611Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Operator(Pauli(label='X')) == Operator(XGate())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that this checks that each matrix element of the operators is approximately equal; two unitaries that differ by a global phase will not be considered equal:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:21.146256Z",
     "start_time": "2019-08-21T09:04:21.141242Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Operator(XGate()) == np.exp(1j * 0.5) * Operator(XGate())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Process Fidelity\n",
    "\n",
    "We may also compare operators using the `process_fidelity` function from the *Quantum Information* module. This is an information theoretic quantity for how close two quantum channels are to each other, and in the case of unitary operators it does not depend on global phase."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:22.171481Z",
     "start_time": "2019-08-21T09:04:22.147477Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Process fidelity = 1.0\n"
     ]
    }
   ],
   "source": [
    "# Two operators which differ only by phase\n",
    "op_a = Operator(XGate()) \n",
    "op_b = np.exp(1j * 0.5) * Operator(XGate())\n",
    "\n",
    "# Compute process fidelity\n",
    "F = process_fidelity(op_a, op_b)\n",
    "print('Process fidelity =', F)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that process fidelity is generally only a valid measure of closeness if the input operators are unitary (or CP in the case of quantum channels), and an exception will be raised if the inputs are not CP."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-08-21T09:04:44.743744Z",
     "start_time": "2019-08-21T09:04:44.734826Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<h3>Version Information</h3><table><tr><th>Qiskit Software</th><th>Version</th></tr><tr><td>Qiskit</td><td>None</td></tr><tr><td>Terra</td><td>0.14.0</td></tr><tr><td>Aer</td><td>0.6.0</td></tr><tr><td>Ignis</td><td>0.3.0</td></tr><tr><td>Aqua</td><td>0.7.0</td></tr><tr><td>IBM Q Provider</td><td>0.6.1</td></tr><tr><th>System information</th></tr><tr><td>Python</td><td>3.7.7 (default, Mar 26 2020, 10:32:53) \n",
       "[Clang 4.0.1 (tags/RELEASE_401/final)]</td></tr><tr><td>OS</td><td>Darwin</td></tr><tr><td>CPUs</td><td>4</td></tr><tr><td>Memory (Gb)</td><td>16.0</td></tr><tr><td colspan='2'>Wed Apr 29 12:36:22 2020 EDT</td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div style='width: 100%; background-color:#d5d9e0;padding-left: 10px; padding-bottom: 10px; padding-right: 10px; padding-top: 5px'><h3>This code is a part of Qiskit</h3><p>&copy; Copyright IBM 2017, 2020.</p><p>This code is licensed under the Apache License, Version 2.0. You may<br>obtain a copy of this license in the LICENSE.txt file in the root directory<br> of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.<p>Any modifications or derivative works of this code must retain this<br>copyright notice, and modified files need to carry a notice indicating<br>that they have been altered from the originals.</p></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import qiskit.tools.jupyter\n",
    "%qiskit_version_table\n",
    "%qiskit_copyright"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
